import Vue from "vue";
import render from "./render/render.js";

function vHandle() {
    this._instance = null
    this._constructor = null
    this._index = 0
}

/*Method: buildConstructor
 *Desc: build vue constructor.
 *Args:
 * constructorOps: Class<Object>, see help document: HELP.CREATE_VNODE.md
*/
vHandle.prototype.buildConstructor = function (constructorOps, vnodes, context = undefined) {
    try {
        this.Debug(['-------------[begin_buildConstructor]-------------'])
        this.Debug([`[vHandle.buildConstructor] create Vue constructor.`])
        if (!constructorOps.hasOwnProperty('render') && !constructorOps.hasOwnProperty('template')) {
            constructorOps["render"] = function (createElement) {
                let _self = this;
                if (vnodes === undefined) {
                    throw new TypeError(`[vHandle] vHandle.buildConstructor param vNodeFunc can not is undefined.`)
                }
                return new render(createElement, vnodes, _self, _self)
            }
        }
        constructorOps[parent] = context
        this._constructor = Vue.extend(constructorOps);
        this.Debug([`[vHandle.buildConstructor] constructor:`, this._constructor])
        //return this._constructor;
    }
    catch (e) {
        throw e;
    }
}

/*Method: instance
 *Desc: instance vue object and mount is.
 *Args:
 * ops: Class<Object>, see help document: Help_CREATE_VNODE.md
*/
vHandle.prototype.instance = function (ops) {
    this.Debug(['-------------[begin_instance]-------------'])
    if (!('type' in ops)) {
        ops['type'] = 'mount'
    }
    if (this.attrChecked(ops, ['el']).status) {
        if (ops.el.indexOf("#") < 0) {
            ops.el = "#" + ops.el
        }
    }
    this.Debug([`[vHandle.instance.ops]:`, ops])
    if (this._constructor) {
        this.Debug([`[vHandle.instance] create Vue instance.`])
        this._instance = new this._constructor(ops);
        this.Debug([`[vHandle.instance] instance`, this._instance])
        if (this._instance) {
            if (ops.on) {
                for (let o in ops.on) {
                    this._instance.$on(o, ops.on[o])
                }
            }
            // Mount.
            if (this.attrChecked(ops, ['type']).status) {
                switch (ops.type.toLowerCase()) {
                    case "append": {
                        if (this.attrChecked(ops, ['el']).status) {
                            let mountBox = document.createElement(ops.dom ? ops.dom : 'div');
                            let mountBoxId = ops.el.replace("#", "") + "_" + (++this._index);
                            mountBox.setAttribute('id', mountBoxId.replace("#", ""));
                            let parentNode = document.getElementById(ops.el.replace('#', ""))
                            if (parentNode != null & parentNode != undefined) {
                                parentNode.appendChild(mountBox)
                            }
                            else {
                                this.Debug([`[vHandle.instance] htmlDom can not found ${ops.el} node.`])
                                throw new ReferenceError("[ERROR] vHandle.instance can not found node.")
                            }
                            this.Debug([`[vHandle.instance] mount to '${ops.el}' element.`])
                            this._instance.$mount("#" + mountBoxId)
                        }
                        break;
                    }
                    case "new": {
                        let mountBox = document.createElement(ops.dom != undefined ? ops.dom : 'div');
                        let mountBoxId = ops.el.replace("#", "") + "_" + (++this._index);
                        mountBox.setAttribute('id', mountBoxId.replace("#", ""));
                        document.body.appendChild(mountBox)
                        this.Debug([`[vHandle.instance] mount to 'body' element.`])
                        this._instance.$mount("#" + mountBoxId)
                        break;
                    }
                    case "mount": {
                        this.Debug([`[vHandle.instance] mount to '${ops.el}' element.`])
                        this._instance.$mount()
                        break;
                    }
                    default: {
                        throw new ReferenceError('[ERROR]:instance Ops type is error, set is \'new\' or \'append\' or \'mount\'');
                    }
                }
            }
        } else {
            throw new ReferenceError("[ERROR]: vHandle instance is null");
        }
    } else {
        throw new ReferenceError("[ERROR]: vHandle constructor is null.");
    }
}
/*
vHandle.prototype.RenderFunc = function (createElement, vNode) {
    return new render(createElement, vNode, this)
}*/
/*Method: vHandle.attrChecked
 *Desc: checked object attribute exist.
 *Args:
 *  target: Class<Object>, source Object.
 *  attributes: Class<[]>, will checking attributes list.
 *  error_break_of: Class<Boolen>, if error will break of, default value is true.
 *Return:
 *  {status: class<Boolen>, msg:""}
*/
vHandle.prototype.attrChecked = function (target, attributes = [], error_break_of = true) {
    for (let o = 0; o < attributes.length; ++o) {
        let v = attributes[o];
        if (!Reflect.has(target, v)) {
            if (error_break_of)
                throw new ReferenceError("[ERROR]: instance ops(" + typeof (target) + ")" + v + " does not exist.");
            else
                this.Debug([`[vHandle.attrChecked] '${v}' does not exist, target:`, target])
            return { status: false, msg: "[ERROR]: instance ops(" + typeof (target) + ")" + v + " does not exist." };
        } else {
            this.Debug([`[vHandle.attrChecked] '${v}' checked success.`])
        }
    }
    return { status: true, msg: "success" };
}

vHandle.prototype.getInstance = function () {
    return this._instance;
}

vHandle.prototype.ISPROCUCTION = function () {
    return process.env.NODE_ENV === 'production' ? true : false
}

vHandle.prototype.Debug = function (info = []) {
    if (!this.ISPROCUCTION()) {
        info.forEach(function (o) {
            console.log("%O", o)
        });
    }
}
const V = new vHandle()
export { V, vHandle }